/**
 * @widoc $.fn.initSelect
 * @namespace comp
 * @des 初始化 select。
 * @type function
 * @param {object} opts
 * @param {string} opts.name 初始化完成后，下拉框元素的 name 属性值，会在 el 中生成 <select name="name"></select>，以便表单取值
 * @param {array=} opts.data [{text(文本):xx,value(值):xx}]
 * @param {string=} opts.txtField 文本字段名(默认为 txt)
 * @param {string=} opts.valField 值字段名(默认为 val)
 * @param {boolean=} opts.readonly 是否为只读，默认为 false
 * @param {boolean=} opts.mulChk:true 默认为复选
 * @param {array=} opts.selParams 选中项条件[key,value]，若为[value]，则key默认为valField, 其中 value 支持 Array
 * @param {function=} opts.callback(selData) 值改变时的回调函数，参数为当前选中项数据，单选返回对象，多选返回对象数组，无选中则为 undefined
 * @return {object|undefined} obj
 * @rtn {function} obj.reset(newOpts) 重置数据源及默认选中项
 * @rtn {function} obj.select(selParams) 选中符合条件的项
 * @rtn {function} obj.getSelect() {object|array} 获取当前选中项的数据，单选返回对象，多选返回对象数组，无选中则为 undefined
 * @rtn {function} obj.getValue() {string} 获取当前选中项的值，无选中则为 -1
 * @rtn {function} obj.setDisabled(readonly) 设置只读状态
 */
$.fn.initSelect = function(opts){
    if(!opts.name){
        console.error('initSelect 初始化时必须传入 name!');
        return;
    }
    opts = $.extend({
        //name:// 多选时必须 初始化完成后，会在 el 后生成 <input type="hidden" name="name" />，以便表单取值
        data: [],
        txtField: 'txt',
        valField: 'val',
        readonly: false,
        mulChk: true,
        //selParams:[key,value],
        callback: $.noop
    }, opts);
    var el = $(this),
        jqSel, jqTxt;
    var api;
    var name, mulChk, txtField, valField, data, readonly;
    var selectIdx;// 记录选中项索引，单选为数字类型，多选为数组类型,无选中项时为 -1
    var nNewSelectIdx,sNewVal,sNewTxt;
    /**
     * 多选 ，根据 selectIdx 设置选中值
     * @param change //select change触发的选中项为true
     */
    var fCheckDom = function(change){
        var curData,//当前数据
            aMultipleData = [], // 选中项文本，值，select设值，数据
            aMultipleVal = [],//多选时的选中项
            sMultipleChange='';//选中项之前多选值
        if($.isArray(nNewSelectIdx)){ //多选的情况nNewSelectIdx是数组
            sNewTxt = '';
            sNewVal = '';
            $.each(nNewSelectIdx, function(index, value){
                curData = data[value];
                sNewTxt += curData[txtField] + ';';
                sNewVal += curData[valField] + ';';
                aMultipleData.push(curData);//多选数据
                aMultipleVal.push(curData[valField]);//多选时的选中项
            });
            if($.isArray(selectIdx)){//selectIdx
                sMultipleChange = selectIdx.join(';');
            }
            if(nNewSelectIdx.join(';')!==sMultipleChange){//新的选中项与select的选中项不一致。发生了改变
                selectIdx = nNewSelectIdx;//更新selectIdx
                if(!change){
                    jqSel.val(aMultipleVal);
                }
                if(change){
                    opts.callback(aMultipleData);
                }
            }
        }
        else{
            if(nNewSelectIdx === -1){ //没有选中项
                sNewTxt = '';
                sNewVal = -1;// 设为-1，清空选中项，避免选中第一项时无法触发事件
            }
            else if(nNewSelectIdx!==selectIdx){ //单选有选中值情况,更新数据
                curData = data[nNewSelectIdx];
                sNewTxt = curData[txtField];
                sNewVal = curData[valField];
            }
            if(nNewSelectIdx!==selectIdx){
                jqSel.val(sNewVal);
                selectIdx = nNewSelectIdx;//更新selectIdx
                if(change){
                    opts.callback(curData);
                }
            }

        }
        if(jqTxt.val()!==sNewTxt){
            jqTxt.val(sNewTxt);
        }
    };
    // 根据最新传入的选中值进行选中操作
    var fSelect = function(selParams,change){
        var key, val;
        if(!data.length){//数据源空
            return;
        }
        if(Object.prototype.toString.call(selParams) !== '[object Array]'){// 不是数组
            selParams = [valField, selParams];
        }
        if(!selParams||!selParams[1] || selParams.length !== 2){ //选中值不存在或者不是[key,value]合法的传参形式
            nNewSelectIdx=-1;//无选中值
        }
        else{
            key = selParams[0];
            val = selParams[1];
            if(!$.isArray(val)){// 字符串。单选多选都能通过单个字符串设置默认选中值
                $.each(data, function(i, item){//遍历数据源
                    if(item[key] === val){// 找到了符合的项
                        nNewSelectIdx = i; //保存新的选中值
                        return false; //跳出循环
                    }
                });
            }
            else{
                if(mulChk){
                    nNewSelectIdx = [];
                }
                $.each(val, function(i, selVal){ //遍历selParams当前选中项数组。单选多选都能通过数组设置默认选中值
                    $.each(data, function(idx, item){//遍历数据源
                        if(item[key] === selVal){// 找到了符合的项
                            if(mulChk){//多选
                                nNewSelectIdx.push(idx);
                            }else{//单选,只有一个选中值
                                nNewSelectIdx = idx;
                                return false;
                            }
                        }
                    });
                });
            }
        }
        fCheckDom(change);// 根据 selectIdx 选中 dom
    };
    //得到选中数据源
    var fGetSelect = function(){
        var selData,
            len;
        if(selectIdx===-1){
            return;
        }
        else if($.isArray(selectIdx)){
            len = selectIdx.length;
            selData = [];
            if(len && data.length){ //索引存在,数据源存在
                for(var i = 0; i < selectIdx.length; i++){
                    selData.push(data[selectIdx[i]]);
                }
            }
            return selData;
        }else{
            return data && (typeof selectIdx!='undefined') ? data[selectIdx] : undefined;
        }
    };
    //得到选中字段值
    var fGetValue = function(){
        var selData=fGetSelect(),//选中数据
            val;
        if(!selData){
            return selectIdx;
        }
        if(mulChk){
            if(selData&&selData.length&&data.length){
                val = '';
                $.each(selData,function(i,item){
                    val+=item[valField]+';';
                });
                return val;
            }
        }else{
            if(selData){
                return selData[valField];
            }
        }
    };
    // 下拉框 change 事件
    var fOnSelChange = function(){
        fSelect([valField,jqSel.val()],true);
    };
    //select框的点击事件
    var fOnTxtTap = function(){
        jqSel.trigger('tap');
    };
    //设置只读状态
    var fSetDisabled = function(stat){
        readonly = stat !== false;// 不定义时设为 true
        if(readonly){
            el.addClass('wi-dp-disabled');
        }
        else{
            el.removeClass('wi-dp-disabled');
        }
        jqSel.prop('disabled', readonly);// 没有readonly状态，只能设为disabled，且通过e.preventDefault()也无法拦截弹出选项
        jqTxt.prop('disabled', readonly);
    };
    //重置数据源及默认选中项
    var fReset = function(cusOpts){
        var sMultiple,
            readOnly;
        if(cusOpts){
            $.extend(opts, cusOpts);
            txtField = opts['txtField'];
            valField = opts['valField'];
            readOnly = cusOpts.readonly;
            sMultiple = mulChk ? 'multiple' : '';//多选属性配置
            if(mulChk){
                selectIdx = [];
            }
            if(cusOpts.data){// 可选列表发生变化，需要重绘组件
                data = opts['data'] || [];// 暂存数据
                var str = '<input class="wi-dp-txt" type="text" readonly />' +
                    '<select class="wi-dp-sel" name="'+name+'" '+sMultiple+'>';
                for(var i = 0, item; i < data.length; i++){
                    item = data[i];
                    str += '<option value="' + item[valField] + '">' + item[txtField] + '</option>'
                }
                str += '</select>';
                el.html(str);
                jqSel = el.find('.wi-dp-sel');
                jqTxt = el.find('.wi-dp-txt');
                // 若数据变更引起重绘，需要重新设置组件各部分只读状态
                fSetDisabled(readOnly === undefined ? readonly : readOnly);
            }
            else if(readOnly !== undefined && readOnly !== readonly){
                fSetDisabled(readOnly);
            }
            fSelect(cusOpts.selParams);// 根据最新传入的选中值进行选中操作
        }
    };
    var init = function(){
        name = opts.name;
        mulChk = opts.mulChk;
        if(($.styleHelper.getValue(el, 'position') || 'static' ) === 'static'){// 因其中 select 采用定位，因此需将 el 设置为参照元素
            el.css('position', 'relative');
        }
        el.prop('readonly', true)// 禁止输入
          .attr('autocomplete', 'off');
        el.addClass('wi-dp')
          .off('change.select')// 解绑原有事件
          .off('tap.select')
          .on('change.select', '.wi-dp-sel', fOnSelChange)
          .on('tap.select', '.wi-dp-txt', fOnTxtTap);//select框的点击事件
        el.data('wiDp', api);
        fReset(opts);
    };
    api = {
        select: fSelect,
        reset: fReset,
        setDisabled: fSetDisabled,
        getSelect: fGetSelect,
        getValue: fGetValue
    };
    init();
    return api;
};